/*
 *  RYMOS
 *  Copyright (C) 2003 - 2012 Roberto Rodriguez 
 *
 *  This program is free software; you can redistribute it and/or modify 
 *  it under the terms of the GNU General Public License as published by 
 *  the Free Software Foundation; either version 2 of the License, or 
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License 
 *  along with this program; if not, write to the Free Software 
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * contact me by e-mail<prfiredragon@gmail.com>
 * 
 *
 *  based on the SoftwareMultitasking tutorial from 
 *  http://code.google.com/p/onyxkernel/wiki/SoftwareMultitasking
 */

#include <task.h>
#include <system.h>

task_t *tasks;
uint32_t curr_pid = -1;
uint32_t taskcount = 0;
uint32_t next_pid = 0;

void dummytask(void)
{
	printf("Dummy Task\n");
}

void init_tasking()
{
	tasks = (task_t*) kmalloc(sizeof(task_t) * 0x400);
	CreateTask("System Task\0", dummytask);		
	curr_pid = 0;
	SetSchedStatus(1);							
}

// Restarts a task from the 'thread' field
void RestartTask()
{	
	if (curr_pid)
		tasks[curr_pid].thread();
	else
		return;
}

// Allows tasks to execute more than 1 thread
// while saving the same context state
void ExecuteOnTask(void (*thread)())
{
	tasks[curr_pid].thread = thread;
	RestartTask();	// Wait until task runs
}

void RemoveTask(int pid)
{
	tasks[pid] = tasks[0];	// system idle task
}

int CreateTask(uint8_t name[32], void (*thread)())
{
	asm volatile("cli");
	int id = next_pid++;

	uint32_t *stack;
	task_t *task = (task_t*) kmalloc(sizeof(task_t));
	task->stack = kmalloc(0x1000) + 0x1000;	// Allocate 4 kilobytes of space
	task->esp = task->stack;

	stack = (uint32_t*)task->stack;

	// processor data (iret)
	*--stack = 0x202;	// EFLAGS
	*--stack = 0x08;	// CS
	*--stack = (uint32_t) thread;	// EIP

	// pusha
	*--stack = 0;		// EDI
	*--stack = 0;		// ESI
	*--stack = 0;		// EBP
	*--stack = 0;		// NULL
	*--stack = 0;		// EBX
	*--stack = 0;		// EDX
	*--stack = 0;		// ECX
	*--stack = 0;		// EAX

	// data segments
	*--stack = 0x10;	// DS
	*--stack = 0x10;	// ES
	*--stack = 0x10;	// FS
	*--stack = 0x10;	// GS

	task->state = 1;
	task->pid = id;
	task->stack = (uint32_t) stack;
	task->thread = thread;
	task->vm86 = 0;
	strncpy(task->name, name, strlen(name));

	tasks[id] = *task;
	
	taskcount++;
	asm volatile("sti");
	return id;
		
}

